from typing import Dict, List, Optional
import pandas as pd
import numpy as np
import pandas_ta as ta
from dataclasses import dataclass

@dataclass
class IndicatorConfig:
    """技术指标配置"""
    rsi_period: int = 14
    macd_fast: int = 12
    macd_slow: int = 26
    macd_signal: int = 9
    bb_period: int = 20
    bb_std: float = 2.0
    atr_period: int = 14
    supertrend_factor: float = 3.0
    supertrend_period: int = 10
    cci_period: int = 20
    mfi_period: int = 14

class TechnicalIndicators:
    """技术指标分析器"""
    
    def __init__(self, config: IndicatorConfig = None):
        """初始化技术指标分析器"""
        self.config = config or IndicatorConfig()
        
    def _ensure_numeric(self, df: pd.DataFrame) -> pd.DataFrame:
        """确保OHLCV数据为数值类型"""
        numeric_df = df.copy()
        for col in ['open', 'high', 'low', 'close', 'volume']:
            if col in numeric_df.columns:
                numeric_df[col] = pd.to_numeric(numeric_df[col], errors='coerce')
        return numeric_df
        
    def calculate_all(self, data: pd.DataFrame) -> pd.DataFrame:
        """计算所有技术指标"""
        try:
            print("开始计算技术指标...")
            
            # 确保数据类型正确
            df = self._ensure_numeric(data.copy())
            
            # 验证数据完整性
            if df['close'].isnull().any():
                raise ValueError("价格数据包含空值")
            
            # 计算各个指标
            indicators = {}
            
            # 确保 volume 列为整数类型
            df['volume'] = df['volume'].astype(np.int64)
            
            # RSI
            df['rsi'] = ta.rsi(df['close'], length=self.config.rsi_period)
            
            # MACD
            macd = ta.macd(df['close'], 
                          fast=self.config.macd_fast, 
                          slow=self.config.macd_slow, 
                          signal=self.config.macd_signal)
            df = pd.concat([df, macd], axis=1)
            
            # Bollinger Bands
            bb = ta.bbands(df['close'], 
                         length=self.config.bb_period, 
                         std=self.config.bb_std)
            df = pd.concat([df, bb], axis=1)
            
            # ATR
            df['atr'] = ta.atr(df['high'], df['low'], df['close'], 
                             length=self.config.atr_period)
            
            # CCI
            df['cci'] = ta.cci(df['high'], df['low'], df['close'], 
                             length=self.config.cci_period)
            
            # MFI
            df['mfi'] = ta.mfi(df['high'], df['low'], df['close'], 
                             df['volume'].astype(np.int64), 
                             length=self.config.mfi_period)
            
            print("技术指标计算完成")
            return df
            
        except Exception as e:
            print(f"计算技术指标时出错: {str(e)}")
            raise
            
    def calculate_custom_features(self, df: pd.DataFrame) -> pd.DataFrame:
        """计算自定义特征"""
        try:
            # 价格变化百分比
            df['price_change_pct'] = df['close'].pct_change()
            
            # 波动率（过去20个周期的收盘价标准差）
            df['volatility'] = df['close'].rolling(window=20).std()
            
            # 成交量变化率
            df['volume_change_pct'] = df['volume'].pct_change()
            
            # 价格趋势（简单移动平均线）
            df['sma_20'] = ta.sma(df['close'], length=20)
            df['sma_50'] = ta.sma(df['close'], length=50)
            
            # 趋势方向（20日均线和50日均线的差值）
            df['trend_strength'] = df['sma_20'] - df['sma_50']
            
            return df
            
        except Exception as e:
            print(f"计算自定义特征时出错: {str(e)}")
            raise

    def get_signal_summary(self, data: pd.DataFrame) -> Dict:
        """获取技术指标信号摘要"""
        try:
            if data.empty:
                return {}
            
            latest = data.iloc[-1]
            signals = {}
            
            # MACD信号
            if all(col in data.columns for col in ['macd', 'macd_signal']):
                macd = latest['macd']
                signal = latest['macd_signal']
                signals['macd_trend'] = 'bullish' if macd > signal else 'bearish'
                signals['macd_value'] = float(macd)
                signals['macd_signal'] = float(signal)
            
            # RSI信号
            if 'rsi' in data.columns:
                rsi = latest['rsi']
                signals['rsi'] = float(rsi)
                if rsi > 70:
                    signals['rsi_signal'] = 'overbought'
                elif rsi < 30:
                    signals['rsi_signal'] = 'oversold'
                else:
                    signals['rsi_signal'] = 'neutral'
            
            # 布林带信号
            bb_cols = ['bb_upper', 'bb_middle', 'bb_lower']
            if all(col in data.columns for col in bb_cols):
                close = latest['close']
                upper = latest['bb_upper']
                lower = latest['bb_lower']
                
                if close > upper:
                    signals['bb_signal'] = 'overbought'
                elif close < lower:
                    signals['bb_signal'] = 'oversold'
                else:
                    signals['bb_signal'] = 'neutral'
            
            # MFI信号
            if 'mfi' in data.columns:
                mfi = latest['mfi']
                signals['mfi'] = float(mfi)
                if mfi > 80:
                    signals['mfi_signal'] = 'overbought'
                elif mfi < 20:
                    signals['mfi_signal'] = 'oversold'
                else:
                    signals['mfi_signal'] = 'neutral'
            
            return signals
            
        except Exception as e:
            print(f"获取信号摘要时出错: {str(e)}")
            return {}
